# Lucid is (C) Copyright 2006-2007 by Infiscape Corporation
#
# This file is part of Lucid, a PyOpenSG example application.
#
# Lucid is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# Lucid is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.

# Environment code
import os, os.path, pickle, time
pj = os.path.join
from pydispatch import dispatcher
import osg2

import lucid.util.plugin
import lucid.util.mixins
import lucid.view
#from lucid.core import signal
import lucid.core


class Environment(lucid.util.mixins.Singleton):
   """ The main environment/namespace for the editor.    
       This class is a singleton.
       
       @var viewer: The viewer mainwindow that is running the application.
       @var pluginManager: The plugin manager for the system.
       @var sceneList: Holds a list of the scenes that we are viewing.
       @var activeScene: The scene that currently has focus.
       @var currentCopy: Root of current tree that is being copied (clipboard)
   """
   def __init__(self):
      if not hasattr(self, '_init_called'):
         self._init_called = True
         self.viewer = None
         self.pluginManager = None
         self.sceneList = []
         self.settings = None
         self.mViewPluginsHolder = None
         self.mDataDir = ""    # The directory to find data files for the app
         
         # Selected items
         # - For now we store these all here as a central point
         #  It may make sense to refactor this in the future
         self._activeScene = None
         self._selectedNode = None
         self._selectedFieldContainer = None
         
         # Copy buffer
         self._currentCopy = None         
   
   def initialize(self, progressCB=None, dataDir=""):
      """ Initialize the environment. """
      # -- Settings --- #
      self.mDataDir = dataDir
      self.loadSettings()
      
      # -- Plugin manager -- #
      self.pluginManager = lucid.util.plugin.PluginManager()
      self.pluginManager.scan(self.settings.plugin_paths, progressCB)
      plugins = self.pluginManager.getPlugins(returnNameDict=True)
      print "Environment found plugins: "      
      for (name,p) in plugins.iteritems():
         print "  %s : %s"%(name,p)
      
      # -- Initialize the plugin holders -- #
      self.mViewPluginsHolder = lucid.core.ViewPluginsHolder()
      self.mViewPluginsHolder.scan()
      
      # --- Viewer -- #      
      self.viewer = lucid.view.Viewer()
   
   # ---- Properties ----- #
   # Use properties for attributes that may need to trigger
   # signals in the system on change.
   def _getActiveScene(self):
      return self._activeScene
   def _setActiveScene(self, scene):
      if self._activeScene != scene:
         self._activeScene = scene      
         dispatcher.send(lucid.core.signal.ActiveSceneChanged, self)
   activeScene = property(_getActiveScene, _setActiveScene)   

   def _getSelectedNode(self):
      return self._selectedNode
   def _setSelectedNode(self, node):
      if self._selectedNode != node:
         self._selectedNode = node
         dispatcher.send(lucid.core.signal.SelectedNodeChanged)
         core = node.getCore()
         self.selectedFC = core         
   selectedNode = property(_getSelectedNode, _setSelectedNode)   
   
   # - Still not sure if it is a good idea to have this in environment
   #   it may make more sense to have these as properties of the plugins
   #   but then how do we access the plugins from other plugins????  
   def _getSelectedFieldContainer(self):
      return self._selectedFieldContainer
   def _setSelectedFieldContainer(self, fc):
      if self._selectedFieldContainer != fc:
         self._selectedFieldContainer = fc
         dispatcher.send(lucid.core.signal.SelectedFieldContainerChanged)
   selectedFC = property(_getSelectedFieldContainer, _setSelectedFieldContainer)
   """ The currently selected field container in the system. """
   
   def _getCurrentCopy(self):
      return self._currentCopy
   def _setCurrentCopy(self,val):
      self._currentCopy = val
   currentCopy = property(_getCurrentCopy, _setCurrentCopy)
   
   # ---- User methods --- #
   def addScene(self, scene):      
      self.sceneList.append(scene)
      dispatcher.send(lucid.core.signal.SceneAdded, self)
      self.activeScene = scene
   
   def addEmptyScene(self):
      """ Add a new empty scene. """
      id = 0
      while 1:
         id += 1
         new_name = "unamed-%s"%(id)
         if not new_name in [s.mName for s in self.sceneList]:
            new_node = osg2.Node.create()
            new_node.setCore(osg2.Group.create())
            self.addScene(lucid.core.Scene(new_node,new_name))
            return
      
      
   def openFile(self, filename):
      new_scene = osg2.SceneFileHandler.the().read(filename)
      if None == new_scene:
         QtGui.QMessageBox.critical(self, "Load Failure.",
               "Failed to load file: [%s]"%filename,
               QtGui.QMessageBox.Ignore|QtGui.QMessageBox.Default|QtGui.QMessageBox.Escape,
               QtGui.QMessageBox.NoButton, QtGui.QMessageBox.NoButton)
      else:
         self.addScene( lucid.core.Scene(new_scene,os.path.basename(filename), filename))
   
   def loadSettings(self):
      filename = self.getSettingsFileName()
      if os.path.exists(filename):
         settings_file = file(filename,'r')
         self.settings = pickle.load(settings_file)         
      else:
         self.settings = Settings()
      self.settings.initialize()

   def saveSettings(self):
      """ Save the settings to disk. """
      # Tell everyone to get their settings saved.
      dispatcher.send(lucid.core.signal.SaveStateForExit, self)
      filename = self.getSettingsFileName()
      if not os.path.exists(os.path.dirname(filename)):
         os.makedirs(os.path.dirname(filename))
      settings_file = file(filename,'w')
      pickle.dump(self.settings, settings_file)
      settings_file.close()
   
   def getSettingsFileName(self):
      file_name = os.path.expanduser(pj('~','.lucid','settings.dump'))
      return file_name




class Settings(object):
   """ Class to capture all system settings. """
   def __init__(self):
      self.plugin_paths = []
      self.settings = {}       # Dictionary to save settings
   
   def initialize(self):
      default_plugin_path = os.path.abspath(pj(os.path.dirname(__file__), "..","plugins"))
      assert os.path.exists(default_plugin_path)
      self.plugin_paths = [default_plugin_path,]
      
      
